﻿using Newtonsoft.Json;
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Onetube.Entities.PlayListQueryResult;
using Onetube.Providers.Interfaces;
using System.Collections.Generic;
using System.Linq;
namespace Onetube.Providers
{
    public class YoutubePlayListProvider : IYoutubePlayListProvider
    {
        private async Task<Entities.PlayListQueryResult.PlayListQueryResult> ResolveRequest(StringBuilder petitionUri, TaskCompletionSource<Entities.PlayListQueryResult.PlayListQueryResult> taskCompletitionSource, CancellationTokenSource cancelTask)
        {
            if (cancelTask == null)
            {
                cancelTask = new CancellationTokenSource();
            }
           
            using (HttpClient client = new HttpClient())
            {
                HttpResponseMessage response = await client.GetAsync(petitionUri.ToString(), cancelTask.Token).ConfigureAwait(false);
                
                string resultJson;
                using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), Encoding.UTF8))
                {
                    try
                    {
                        resultJson = await reader.ReadToEndAsync().ConfigureAwait(false);

                        if (!string.IsNullOrEmpty(resultJson))
                        {
                            var entries = JsonConvert.DeserializeObject<PlayListQueryResult>(resultJson);

                            taskCompletitionSource.SetResult(entries);
                            resultJson = null;
                            entries = null;
                        }
                        else
                        {
                            taskCompletitionSource.SetResult(null);
                        }
                        response.Dispose();
                    }
                    catch (Exception ex)
                    {
                        taskCompletitionSource.SetException(ex);
                    }
                }
            }
            return await taskCompletitionSource.Task;
        }

        public async Task<Models.SearchPlayListResult> SearchPlayListByChannelIdAsync(string id, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/playlists?");

            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&channelId={0}", id);
        
            // petitionUri.AppendFormat("&pageToken={0}", nextPageToken);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);

            var taskCompletitionSource = new TaskCompletionSource<Entities.PlayListQueryResult.PlayListQueryResult>();
            
            var result= await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);
          
            var list = new Models.SearchPlayListResult();
            list.Items = new List<Entities.PlayListQueryResult.Item>();
            list.Items = new List<Entities.PlayListQueryResult.Item>();
            if (result != null)
            {
                var playListItemProvider = new Providers.YoutubePlayListItemProvider();
                list.NextPageToken = result.NextPageToken;

                if (result.Items!=null && result.Items.Any())
                {
                    foreach (var item in result.Items)
                    {
                        var info = await playListItemProvider.GetPlayListInfoAsync(item.Id, "1", cancelTask).ConfigureAwait(false);
                        var listItem = new Entities.PlayListQueryResult.Item();
                        listItem.Id = item.Id;
                        listItem.Kind = item.Kind;
                        var snippet = new Entities.PlayListQueryResult.Snippet();
                        snippet.ChannelId = item.Snippet.ChannelId;
                        snippet.ChannelTitle = item.Snippet.ChannelTitle;
                        snippet.Title = item.Snippet.Title;
                        snippet.Thumbnails = new Entities.PlayListQueryResult.Thumbnails
                        {
                            Default = new Entities.PlayListQueryResult.Default { Url = item.Snippet.Thumbnails.Default.Url },
                            Medium = new Entities.PlayListQueryResult.Medium { Url = item.Snippet.Thumbnails.Medium.Url },
                            High = new Entities.PlayListQueryResult.High { Url = item.Snippet.Thumbnails.High.Url }
                        };
                        listItem.Snippet = snippet;
                        listItem.VideosCount = info.PageInfo.TotalResults;
                        info = null;
                        list.Items.Add(listItem);
                    }
                }
            }
            result = null;
            return list;
        }

        public Task<Models.SearchPlayListResult> SearchPlayListByChannelIdPrevAsync(string prevPageToken, string id, string maxResults, CancellationTokenSource cancelTask)
        {
            return null;
        }

        public async Task<Models.SearchPlayListResult> SearchPlayListByChannelIdNextAsync(string nextPageToken, string id, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/playlists?");

            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&channelId={0}", id);

            petitionUri.AppendFormat("&pageToken={0}", nextPageToken);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);

            var taskCompletitionSource = new TaskCompletionSource<Entities.PlayListQueryResult.PlayListQueryResult>();

            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);

            var list = new Models.SearchPlayListResult();
            list.Items = new List<Entities.PlayListQueryResult.Item>();
            list.Items = new List<Entities.PlayListQueryResult.Item>();
            if (result != null)
            {
                var playListItemProvider = new Providers.YoutubePlayListItemProvider();
                list.NextPageToken = result.NextPageToken;

                if (result.Items.Any())
                {
                    foreach (var item in result.Items)
                    {
                        var info = await playListItemProvider.GetPlayListInfoAsync(item.Id, "1", cancelTask).ConfigureAwait(false);
                        var listItem = new Entities.PlayListQueryResult.Item();
                        listItem.Id = item.Id;
                        listItem.Kind = item.Kind;
                        var snippet = new Entities.PlayListQueryResult.Snippet();
                        snippet.ChannelId = item.Snippet.ChannelId;
                        snippet.ChannelTitle = item.Snippet.ChannelTitle;
                        snippet.Title = item.Snippet.Title;
                        snippet.Thumbnails = new Entities.PlayListQueryResult.Thumbnails
                        {
                            Default = new Entities.PlayListQueryResult.Default { Url = item.Snippet.Thumbnails.Default.Url },
                            Medium = new Entities.PlayListQueryResult.Medium { Url = item.Snippet.Thumbnails.Medium.Url },
                            High = new Entities.PlayListQueryResult.High { Url = item.Snippet.Thumbnails.High.Url }
                        };
                        listItem.Snippet = snippet;
                        listItem.VideosCount = info.PageInfo.TotalResults;
                        info = null;
                        list.Items.Add(listItem);
                    }
                }
            }
            result = null;
            return list;
        }

        public Task<Entities.PlayListQueryResult.PlayListQueryResult> GetMyPlayListsAsync(string token, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/playlists?");

            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&mine={0}", "true");
        
            // petitionUri.AppendFormat("&pageToken={0}", nextPageToken);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);
            var taskCompletitionSource = new TaskCompletionSource<PlayListQueryResult>();
            HttpWebRequest request = HttpWebRequest.CreateHttp(petitionUri.ToString());
            request.Headers["Authorization"] = "Bearer  " + token;
            
            return ResolveRequest(request, taskCompletitionSource, cancelTask);
        }

        public Task<Entities.PlayListQueryResult.PlayListQueryResult> GetMyPlayListsNextPageAsync(string token, string maxResults, string nextPageToken, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/playlists?");

            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&mine={0}", "true");
            petitionUri.AppendFormat("&pageToken={0}", nextPageToken);
            // petitionUri.AppendFormat("&pageToken={0}", nextPageToken);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);
            var taskCompletitionSource = new TaskCompletionSource<PlayListQueryResult>();
            HttpWebRequest request = HttpWebRequest.CreateHttp(petitionUri.ToString());
            request.Headers["Authorization"] = "Bearer  " + token;
            
            return ResolveRequest(request, taskCompletitionSource, cancelTask);
        }

        public Task<PlayListQueryResult> GetPlayPlistByIdAsync(string id, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/playlists?");

            petitionUri.AppendFormat("part={0}", "snippet");
              petitionUri.AppendFormat("&id={0}", id);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);
            var taskCompletitionSource = new TaskCompletionSource<PlayListQueryResult>();
          
            return ResolveRequest(petitionUri, taskCompletitionSource, cancelTask);
        }

        private async Task<PlayListQueryResult> ResolveRequest(HttpWebRequest request, TaskCompletionSource<PlayListQueryResult> taskCompletitionSource, CancellationTokenSource cancelTask)
        {
            if (cancelTask == null)
            {
                cancelTask = new CancellationTokenSource();
            }
           
            using (HttpClient client = new HttpClient())
            {
                client.DefaultRequestHeaders.Add("Authorization", request.Headers["Authorization"]);
                HttpResponseMessage response = await client.GetAsync(request.RequestUri.ToString(), cancelTask.Token).ConfigureAwait(false);
                
                string resultJson;
                using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), Encoding.UTF8))
                {
                    try
                    {
                        resultJson = await reader.ReadToEndAsync().ConfigureAwait(false);

                        if (!string.IsNullOrEmpty(resultJson))
                        {
                            var entries = JsonConvert.DeserializeObject<PlayListQueryResult>(resultJson);

                            taskCompletitionSource.SetResult(entries);
                            resultJson = null;
                            entries = null;
                        }
                        else
                        {
                            taskCompletitionSource.SetResult(null);
                        }
                        response.Dispose();
                    }
                    catch (Exception ex)
                    {
                        taskCompletitionSource.SetException(ex);
                    }
                }
            }
            return await taskCompletitionSource.Task;
        }


        
    }
}